﻿namespace GenericMatrix
{
    using System;
    using System.Collections;

    public class GenericMatrix<T> where T : IComparable
    {
        //// Define a class Matrix<T> to hold a matrix of numbers (e.g. integers, floats, decimals).
        //// Implement an indexer this[row, col] to access the inner matrix cells.
        //// Implement the operators + and - (addition and subtraction of matrices of the same size) and * for matrix multiplication.
        //// Throw an exception when the operation cannot be performed. Implement the true operator (check for non-zero elements).

        private T[,] coreMatrix;

        public GenericMatrix(int rows, int cols)
        {
            this.coreMatrix = new T[rows, cols];
        }

        public T this[int row, int col]
        {
            get
            {
                return this.coreMatrix[row, col];
            }

            set
            {
                this.coreMatrix[row, col] = value;
            }
        }

        public static GenericMatrix<T> operator +(GenericMatrix<T> first, GenericMatrix<T> second)
        {
            if ((first.coreMatrix.GetLength(0) != second.coreMatrix.GetLength(0)) || (first.coreMatrix.GetLength(1) != second.coreMatrix.GetLength(1)))
            {
                throw new InvalidOperationException("The X and Y dimensions of the first matrix must be equal with the dimensions of the second one");
            }

            GenericMatrix<T> result = new GenericMatrix<T>(first.coreMatrix.GetLength(0), second.coreMatrix.GetLength(1));

            for (int row = 0; row < first.coreMatrix.GetLength(0); row++)
            {
                for (int col = 0; col < first.coreMatrix.GetLength(1); col++)
                {
                    result[row, col] = (dynamic)first.coreMatrix[row, col] + (dynamic)second.coreMatrix[row, col];
                }
            }

            return result;
        }

        public static GenericMatrix<T> operator -(GenericMatrix<T> first, GenericMatrix<T> second)
        {
            if ((first.coreMatrix.GetLength(0) != second.coreMatrix.GetLength(0)) || (first.coreMatrix.GetLength(1) != second.coreMatrix.GetLength(1)))
            {
                throw new InvalidOperationException("The X and Y dimensions of the first matrix must be equal with the dimensions of the second one");
            }

            GenericMatrix<T> result = new GenericMatrix<T>(first.coreMatrix.GetLength(0), second.coreMatrix.GetLength(1));

            for (int row = 0; row < first.coreMatrix.GetLength(0); row++)
            {
                for (int col = 0; col < first.coreMatrix.GetLength(1); col++)
                {
                    result[row, col] = (dynamic)first.coreMatrix[row, col] - (dynamic)second.coreMatrix[row, col];
                }
            }

            return result;
        }

        public static GenericMatrix<T> operator *(GenericMatrix<T> first, GenericMatrix<T> second)
        {
            if ((first.coreMatrix.GetLength(0) != second.coreMatrix.GetLength(0)) || (first.coreMatrix.GetLength(1) != second.coreMatrix.GetLength(1)))
            {
                throw new InvalidOperationException("Both matrices must have equal dimensions");
            }

            GenericMatrix<T> result = new GenericMatrix<T>(first.coreMatrix.GetLength(0), second.coreMatrix.GetLength(1));

            for (int row = 0; row < first.coreMatrix.GetLength(0); row++)
            {
                for (int col = 0; col < first.coreMatrix.GetLength(1); col++)
                {
                    result[row, col] = (dynamic)first.coreMatrix[row, col] * (dynamic)second.coreMatrix[row, col];
                }
            }

            return result;
        }

        public static bool operator true(GenericMatrix<T> wtfQuestionMark)
        {
            bool result = false;

            for (int row = 0; row < wtfQuestionMark.coreMatrix.GetLength(0); row++)
            {
                for (int col = 0; col < wtfQuestionMark.coreMatrix.GetLength(1); col++)
                {
                    if (wtfQuestionMark[row, col].CompareTo(0) == 0)
                    {
                        //result = true;
                        //break;
                        return true;
                    }
                }
            }

            return result;
        }

        public static bool operator false(GenericMatrix<T> wtfQuestionMark)
        {
            bool result = false;

            for (int row = 0; row < wtfQuestionMark.coreMatrix.GetLength(0); row++)
            {
                for (int col = 0; col < wtfQuestionMark.coreMatrix.GetLength(1); col++)
                {
                    if (wtfQuestionMark[row, col].CompareTo(0) == 0)
                    {
                        //result = true;
                        //break;
                        return false;
                    }
                }
            }

            return result;
        }
    }
}